﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.CodeDom;

namespace Devtm.Generator
{
    

    public static class CodeHelper
    {

        public static void Import(this CodeNamespace self, params Type[] types)
        {
            foreach (var item in types)
                self.Imports.Add(new CodeNamespaceImport(item.Namespace));

        }

        public static void Import(this CodeNamespace self, params string[] types)
        {
            foreach (var item in types)
                self.Imports.Add(new CodeNamespaceImport(item));

        }


        public static void Add(this CodeNamespaceImportCollection self, params Type[] types)
        {
            foreach (var item in types)
                self.Add(new CodeNamespaceImport(item.Namespace));

        }

        public static void Add(this CodeNamespaceImportCollection self, params string[] types)
        {
            foreach (var item in types)
                self.Add(new CodeNamespaceImport(item));

        }


        public static CodeTypeDeclaration AddClass(this CodeNamespace parent, MemberAttributes memberAttribute, string className, string inheritFrom = "")
        {
            return AddClass(parent, memberAttribute, className, string.IsNullOrEmpty(inheritFrom) ? null : inheritFrom.TypeReference(), true);
        }

        public static CodeTypeDeclaration AddClass(this CodeNamespace parent, MemberAttributes memberAttribute, string className, CodeTypeReference inheritFrom = null, bool isPartial = true)
        {

            CodeTypeDeclaration t = new CodeTypeDeclaration(className);

            t.IsClass = true;
            t.IsPartial = isPartial;
            t.Attributes = memberAttribute;

            if (inheritFrom != null)
                t.BaseTypes.Add(inheritFrom);

            parent.Types.Add(t);

            return t;
        }


        public static CodeTypeDeclaration AddStruct(this CodeNamespace parent, MemberAttributes memberAttribute, string className, string inheritFrom = "", bool isPartial = true)
        {
            return AddStruct(parent, memberAttribute, className, string.IsNullOrEmpty(inheritFrom) ? null : inheritFrom.TypeReference(), isPartial);
        }
        
        public static CodeTypeDeclaration AddStruct(this CodeNamespace parent, MemberAttributes memberAttribute, string className, CodeTypeReference inheritFrom = null, bool isPartial = true)
        {

            CodeTypeDeclaration t = new CodeTypeDeclaration(className);

            t.IsStruct = true;
            t.IsPartial = isPartial;
            t.Attributes = memberAttribute;

            if (inheritFrom != null)
                t.BaseTypes.Add(inheritFrom);

            parent.Types.Add(t);

            return t;
        }


        public static CodeTypeDeclaration AddEnum(this CodeNamespace parent, MemberAttributes memberAttribute, string className, Type inheritFrom = null, bool isPartial = true)
        {

            CodeTypeDeclaration t = new CodeTypeDeclaration(className);

            t.IsEnum = true;
            t.IsPartial = isPartial;
            t.Attributes = memberAttribute;

            if (inheritFrom != null)
                t.BaseTypes.Add(inheritFrom);

            parent.Types.Add(t);

            return t;
        }


        public static CodeTypeDeclaration AddInterface(this CodeNamespace parent, MemberAttributes memberAttribute, string className, string inheritFrom = "")
        {
            return AddInterface(parent, memberAttribute, className, string.IsNullOrEmpty(inheritFrom) ? null : inheritFrom.TypeReference());
        }

        public static CodeTypeDeclaration AddInterface(this CodeNamespace parent, MemberAttributes memberAttribute, string className, CodeTypeReference inheritFrom = null)
        {

            CodeTypeDeclaration t = new CodeTypeDeclaration(className);

            t.IsInterface = true;
            t.Attributes = memberAttribute;

            if (inheritFrom != null)
                t.BaseTypes.Add(inheritFrom);

            parent.Types.Add(t);

            return t;
        }


        public static void Set(this CodeStatementCollection parent, CodeExpression left, CodeExpression right)
        {
            parent.Add(new CodeAssignStatement(left, right));
        }



        public static CodeParameterDeclarationExpression Parameter(this string self, CodeTypeReference p)
        {
            return new CodeParameterDeclarationExpression(p, self);
        }


        public static CodeVariableReferenceExpression Value()
        {
            return new CodeVariableReferenceExpression("value");
        }


        public static CodePrimitiveExpression Primitive(this string value)
        {
            return new CodePrimitiveExpression(value);
        }

        public static CodePrimitiveExpression Primitive(this Int16 value)
        {
            return new CodePrimitiveExpression(value);
        }

        public static CodePrimitiveExpression Primitive(this Int32 value)
        {
            return new CodePrimitiveExpression(value);
        }

        public static CodePrimitiveExpression Primitive(this Int64 value)
        {
            return new CodePrimitiveExpression(value);
        }

        public static CodePrimitiveExpression Primitive(this bool value)
        {
            return new CodePrimitiveExpression(value);
        }

        public static CodePrimitiveExpression Primitive(this byte value)
        {
            return new CodePrimitiveExpression(value);
        }



        public static CodeVariableReferenceExpression Var(this string varName)
        {
            return new CodeVariableReferenceExpression(varName);
        }

        public static CodePrimitiveExpression Var(this Int16 value)
        {
            return new CodePrimitiveExpression(value);
        }

        public static CodePrimitiveExpression Var(this Int32 value)
        {
            return new CodePrimitiveExpression(value);
        }

        public static CodePrimitiveExpression Var(this Int64 value)
        {
            return new CodePrimitiveExpression(value);
        }



        public static CodeFieldReferenceExpression Reference(this CodeMemberField field)
        {
            return new CodeFieldReferenceExpression(This, field.Name);
        }

        public static CodeFieldReferenceExpression Reference(this CodeMemberField field, CodeExpression targetObject)
        {
            return new CodeFieldReferenceExpression(targetObject, field.Name);
        }


        public static CodePropertyReferenceExpression Reference(this CodeMemberProperty field)
        {
            return new CodePropertyReferenceExpression(This, field.Name);
        }

        public static CodePropertyReferenceExpression Reference(this CodeMemberProperty field, CodeExpression targetObject)
        {
            return new CodePropertyReferenceExpression(targetObject, field.Name);
        }


        public static CodeTypeReference TypeReference(this Type type)
        {
            var t = Devtm.Writers.TypeReference.Get(type);
            return t;
        }

        public static CodeTypeReference TypeReference(this string type)
        {
            var t = Devtm.Writers.TypeReference.Get(type);
            return t;
        }

        public static CodeTypeReference TypeReference(this CodeTypeParameter type)
        {
            var t = Devtm.Writers.TypeReference.Get(type);
            return t;
        }

        public static CodeTypeParameter TypeParameter(this string type)
        {
            var t = new CodeTypeParameter(type);
            return t;
        }

        public static CodeTypeReference AddTypeParameter(this CodeTypeReference self, string type)
        {
            self.TypeArguments.Add(type);
            return self;
        }

        public static CodeTypeReference AddTypeParameter(this CodeTypeReference self, CodeTypeReference type)
        {
            self.TypeArguments.Add(type);
            return self;
        }

        public static CodeTypeReference AddTypeParameter(this CodeTypeReference self, Type type)
        {
            self.TypeArguments.Add(type);
            return self;
        }

       
        public static CodeMethodInvokeExpression CallMethod(this CodeStatementCollection self, string methodName, params CodeExpression[] p)
        {
            var c = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), methodName);
            c.Parameters.AddRange(p);
            self.Add(c);
            return c;
        }

        public static CodeMethodInvokeExpression CallBaseMethod(this CodeStatementCollection self, string methodName, params CodeExpression[] p)
        {
            var c = new CodeMethodInvokeExpression(new CodeBaseReferenceExpression(), methodName);
            c.Parameters.AddRange(p);
            self.Add(c);
            return c;
        }
        
        public static CodeMethodInvokeExpression CallMethod(this CodeStatementCollection self, CodeExpression instance, string methodName, params CodeExpression[] p)
        {
            var c = new CodeMethodInvokeExpression(instance, methodName);
            c.Parameters.AddRange(p);
            self.Add(c);
            return c;
        }

        public static CodeMethodInvokeExpression CallMethod(this CodeExpression self, string methodName, params CodeExpression[] p)
        {
            var c = new CodeMethodInvokeExpression(self, methodName);
            c.Parameters.AddRange(p);
            return c;
        }

        public static CodeMethodInvokeExpression CallMethod(this CodeExpression self, string methodName, CodeTypeReference[] types , params CodeExpression[] p)
        {

            var cc = new CodeMethodReferenceExpression(self, methodName);
        
            foreach (var type in types)
                cc.TypeArguments.Add(type);

            var c = new CodeMethodInvokeExpression(cc, p);
            
            return c;
        
        }

        public static CodeArgumentReferenceExpression Argument(this string self)
        {
            return new CodeArgumentReferenceExpression(self);
        }


        public static CodeConditionStatement If(this CodeStatementCollection self, CodeExpression condition)
        {
            var c = new CodeConditionStatement(condition);
            self.Add(c);
            return c;
        }

        public static CodeExpression IsNull(this CodeExpression item)
        {
            var c = new CodeBinaryOperatorExpression(item, CodeBinaryOperatorType.IdentityEquality, CodeHelper.Null);
            return c;
        }

        public static CodeExpression IsNotNull(this CodeExpression item)
        {
            var c = new CodeBinaryOperatorExpression(item, CodeBinaryOperatorType.IdentityInequality, CodeHelper.Null);
            return c;
        }

        public static CodePrimitiveExpression Null
        {
            get
            {
                return new CodePrimitiveExpression(null);
            }
        }

        public static CodeThisReferenceExpression This
        {
            get
            {
                return new CodeThisReferenceExpression();
            }
        }

        public static CodeBaseReferenceExpression Base
        {
            get
            {
                return new CodeBaseReferenceExpression();
            }
        }

        public static CodeMethodReturnStatement Return(this CodeStatementCollection self, CodeExpression e)
        {
            var r = new CodeMethodReturnStatement(e);
            self.Add(r);
            return r;
        }

    }


}
